var Log = require('../../../util/logger');
var path = require('path');
var util = require('../../../util/index');
var notify = require('../../notify/ui');
var fs = require('fs');
var frac = require('../../../util/frac');
var logger = require('../../../util/logger');

var ret = {
    BEAT_DIVIDE : 16,
    TOUCH : 0,
    SIDE_DRAW : 1,
    HOLD : 2,
    POLY_TRANS_NO_DELAY : 33,
    POLY_TRANS_DELAY : 34,
    POLY_START_NO_DELAY : 97,
    POLY_START_DELAY : 98,
    POLY_END_NO_DELAY : 161,
    POLY_END_DELAY : 162,

    getNote : function(fn) {
        var ret = {
            meta: {
                song: {},
                mode: 0,
                mode_ext: {

                }
            },
            time: [
                {
                    beat: [
                        0,
                        0,
                        1
                    ],
                    time: 0
                }
            ],
            note: [],
            extra: {
                samples: [],
                toggle : [0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0]
            }
        };
        var raw = fs.readFileSync(fn);
        var len = this.byte2int32LE(raw, 0);
        logger.log("beatmap length = " + len + "ms");
        var area2Len = this.byte2int32LE(raw, 4) - 1;
        // calc bpm
        var bpm = +this.calcBpm(raw, area2Len);
        ret.time[0].bpm = bpm;
        logger.log("bpm = " + bpm);
        // get notes
        var result = this.getNotes(raw, 20 + area2Len * 12, bpm);
        ret.note = result.notes;
        // ensure columns
        ret.meta.mode_ext.column = result.colCount;
        for(var i=0;i<result.colCount;i++){
            ret.extra.toggle[i] = 1;
        }
        ret.extra.toggle[result.colCount] = 2;
        // try to get bgm and bg
        var basename = path.basename(fn);
        var dir = path.dirname(fn);
        var tmp = basename.split("_");
        if(tmp.length == 3){
            // filename should like songname_4k_hd.imd;
            var cover = dir + "/" + tmp[0] + ".png";
            if(fs.existsSync(cover)){
                ret.meta.background = tmp[0] + ".png";
            }
            var bgm = dir + "/" + tmp[0] + ".mp3";
            if(fs.existsSync(bgm)){
                ret.note.push({
                    column : result.colCount,
                    sound : tmp[0] + ".mp3",
                    type : 1,
                    beat : [0,0,1]
                });
            }
        }
        return ret;
    },

    calcBpm : function(bArr, len){
        var lastTime = 0;
        var sum = 0;
        for(var i=0;i<len-1;i++){
            var curr = this.byte2int32LE(bArr, 20 + i*12);
            sum += curr - lastTime;
            lastTime = curr;
        }
        return (60000 / (sum / (len-1))).toFixed(2);
    },

    getNotes : function(bArr, offset, bpm){
        var result = {};
        var notes = [];
        var delta = null;
        var divideBeatTime = 60000 / bpm / this.BEAT_DIVIDE;
        var beatTime = 60000 / bpm;
        var noteCount = this.byte2int16LE(bArr, offset+2);
        var colCount = 0;
        logger.log("note count = " + noteCount);
        for(var i=0;i<noteCount;i++){
            var noteOffset = offset + 8 + i * 11;
            var ts = this.byte2int32LE(bArr, noteOffset);
            var col = bArr[noteOffset + 4];
            var delay = this.byte2int32LE(bArr, noteOffset + 5);
            var type = this.byte2int16LE(bArr, noteOffset - 2);
            if(delta === null){
                delta = Math.ceil(ts / divideBeatTime) * divideBeatTime - ts;
                logger.log("global offset = " + delta);
            }
            ts += delta;
            var beat = Math.floor(ts / beatTime);
            var subBeat = Math.floor((ts % beatTime) / divideBeatTime);
            var note = {
                beat : [beat, subBeat, 16],
                column : col
            }
            if(col > colCount){
                colCount = col;
            }
            if(type == this.HOLD || type == this.POLY_TRANS_DELAY || type == this.POLY_START_DELAY || type == this.POLY_END_DELAY){
                if(delay - ts < 20*1000){
                    var endBeat =  Math.floor((ts + delay) / beatTime);
                    var endSubBeat = Math.floor(((ts + delay) % beatTime) / divideBeatTime);
                    note.endbeat = [endBeat, endSubBeat, 16];
                }
            }else if(type == this.POLY_TRANS_NO_DELAY || type == this.POLY_END_NO_DELAY){
                continue;
            }
            logger.log(util.formatStr("[{1}]o={0} ts={2}({5}-{6}) col={3} type={4}",[noteOffset, i, ts, col, type, beat, subBeat]));
            notes.push(note);
            if(offset > bArr.length){
                // quit for wrong note count
                break;
            }
        }
        result.notes = notes;
        result.colCount = colCount + 1;
        result.offset = delta;
        return result;
    },

    /*---------tool functions----------*/
    byte2int32LE : function(bArr, offset){
        return bArr[offset] + bArr[offset+1] * 256 + bArr[offset+2] *65536 + bArr[offset + 3] * 16777216;
    },

    byte2int32BE : function(bArr, offset){
        return bArr[offset]*16777216 + bArr[offset+1] * 65536 + bArr[offset+2] *256 + bArr[offset + 3];
    },

    byte2int16LE : function(bArr, offset){
        return bArr[offset] + bArr[offset+1] * 256;
    }
};

module.exports = ret;